package com.sgcc.nfc.lock.presentation.nfc

import android.app.Activity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import android.content.res.ColorStateList
import android.view.View
import android.widget.ArrayAdapter
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar
import com.sgcc.nfc.lock.R
import com.sgcc.nfc.lock.databinding.ActivityNfcOperationBinding
import com.sgcc.nfc.lock.presentation.rooms.LocationPickerActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class NfcOperationActivity : AppCompatActivity() {

    private lateinit var binding: ActivityNfcOperationBinding
    private val viewModel: NfcOperationViewModel by viewModels()
    private var nfcAdapter: NfcAdapter? = null
    private var roomItems: List<RoomOption> = emptyList()
    private val expectedLockId: String? by lazy { intent.getStringExtra(NfcOperationViewModel.EXTRA_LOCK_NFC_ID) }

    private val pickLocationLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val data = result.data ?: return@registerForActivityResult
            val latitude = data.getDoubleExtra(LocationPickerActivity.EXTRA_LATITUDE, Double.NaN)
            val longitude = data.getDoubleExtra(LocationPickerActivity.EXTRA_LONGITUDE, Double.NaN)
            if (!latitude.isNaN() && !longitude.isNaN()) {
                viewModel.updateLocation(latitude, longitude)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityNfcOperationBinding.inflate(layoutInflater)
        setContentView(binding.root)

        nfcAdapter = NfcAdapter.getDefaultAdapter(this)
        if (nfcAdapter == null || !(nfcAdapter?.isEnabled ?: false)) {
            Snackbar.make(binding.root, getString(R.string.nfc_prompt_title), Snackbar.LENGTH_LONG).show()
        }

        setupToolbar()
        setupRoomDropdown()
        setupListeners()
        observeViewModel()
    }

    override fun onResume() {
        super.onResume()
        enableForegroundDispatch()
    }

    override fun onPause() {
        super.onPause()
        disableForegroundDispatch()
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        if (intent == null) return
        val tag: Tag? = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
        tag?.let { viewModel.onTagDetected(it) }
    }

    private fun observeViewModel() {
        viewModel.uiState.observe(this) { state ->
            renderMode(state.mode)
            updateRoomOptions(state)
            binding.nfcStatus.text = state.statusText
            binding.nfcProgress.isVisible = state.isProcessing || state.addLockInProgress
            binding.nfcProgress.isIndeterminate = state.chargeProgress == null
            state.chargeProgress?.let { progress ->
                binding.nfcProgress.setProgressCompat(progress, true)
            }
            updateStatusVisual(state.result)

            binding.addLockButton.isVisible = state.showAddLockPrompt
            binding.addLockButton.isEnabled = !state.addLockInProgress
            binding.addLockButton.text = if (state.addLockInProgress) {
                getString(R.string.common_loading)
            } else {
                getString(R.string.nfc_add_lock_button)
            }

            binding.roomCard.isVisible = state.showAddLockPrompt
            binding.locationCard.isVisible = state.showAddLockPrompt
            binding.roomLayout.isEnabled = state.showAddLockPrompt
            binding.roomDropdown.isEnabled = state.showAddLockPrompt
            binding.pickLocationButton.isEnabled = state.showAddLockPrompt

            val locationText = if (state.showAddLockPrompt && state.latitude != null && state.longitude != null) {
                getString(R.string.nfc_location_format, state.latitude, state.longitude)
            } else {
                getString(R.string.nfc_location_placeholder)
            }
            binding.locationValue.text = locationText

            val selectedName = if (state.showAddLockPrompt) state.selectedRoom?.roomName.orEmpty() else ""
            if (state.showAddLockPrompt) {
                if (selectedName.isNotBlank() && binding.roomDropdown.text.toString() != selectedName) {
                    binding.roomDropdown.setText(selectedName, false)
                }
            } else if (binding.roomDropdown.text?.isNotEmpty() == true) {
                binding.roomDropdown.text?.clear()
            }
            binding.roomLayout.helperText = if (state.showAddLockPrompt) state.selectedRoom?.address else null

            if (state.message.isNullOrBlank()) {
                binding.messageText.isVisible = false
            } else {
                val messageColorAttr = if (state.result == false) {
                    com.google.android.material.R.attr.colorError
                } else {
                    com.google.android.material.R.attr.colorSecondary
                }
                binding.messageText.setTextColor(MaterialColors.getColor(binding.messageText, messageColorAttr))
                val hint = getString(R.string.nfc_message_tap_to_dismiss)
                binding.messageText.text = buildString {
                    append(state.message)
                    if (!state.message.endsWith(hint)) {
                        append("\n")
                        append(hint)
                    }
                }
                binding.messageText.isVisible = true
            }
        }
    }

    private fun renderMode(mode: NfcOperationViewModel.Mode) {
        val chipText: Int
        val subtitleText: Int
        val chipColorAttr: Int
        val chipOnColorAttr: Int
        when (mode) {
            NfcOperationViewModel.Mode.OPEN -> {
                chipText = R.string.nfc_mode_open
                subtitleText = R.string.nfc_operation_subtitle_open
                chipColorAttr = com.google.android.material.R.attr.colorPrimary
                chipOnColorAttr = com.google.android.material.R.attr.colorOnPrimary
            }
            NfcOperationViewModel.Mode.CLOSE -> {
                chipText = R.string.nfc_mode_close
                subtitleText = R.string.nfc_operation_subtitle_close
                chipColorAttr = com.google.android.material.R.attr.colorTertiary
                chipOnColorAttr = com.google.android.material.R.attr.colorOnTertiary
            }
        }
        binding.modeChip.text = getString(chipText)
        binding.headerSubtitle.text = buildString {
            append(getString(subtitleText))
            expectedLockId?.let {
                append("（标签: ")
                append(it)
                append("）")
            }
        }
        val chipColor = MaterialColors.getColor(binding.modeChip, chipColorAttr)
        val chipOnColor = MaterialColors.getColor(binding.modeChip, chipOnColorAttr)
        binding.modeChip.chipBackgroundColor = ColorStateList.valueOf(chipColor)
        binding.modeChip.setTextColor(chipOnColor)
    }

    private fun updateRoomOptions(state: NfcOperationUiState) {
        if (roomItems.map { it.id } != state.rooms.map { it.roomId }) {
            roomItems = state.rooms.map { room ->
                RoomOption(room.roomId, room.roomName ?: getString(R.string.nfc_room_hint))
            }
            val labels = roomItems.map { it.label }
            val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, labels)
            binding.roomDropdown.setAdapter(adapter)
        }
    }

    private fun updateStatusVisual(result: Boolean?) {
        val statusColorAttr = when (result) {
            true -> com.google.android.material.R.attr.colorPrimary
            false -> com.google.android.material.R.attr.colorError
            else -> com.google.android.material.R.attr.colorOnSurfaceVariant
        }
        val color = MaterialColors.getColor(binding.statusLabel, statusColorAttr)
        binding.statusLabel.setTextColor(color)
    }

    private fun setupToolbar() {
        binding.toolbar.setNavigationOnClickListener { finish() }
    }

    private fun setupRoomDropdown() {
        binding.roomDropdown.setOnItemClickListener { _, _, position, _ ->
            roomItems.getOrNull(position)?.id?.let { viewModel.selectRoom(it) }
        }
        binding.roomDropdown.setOnClickListener { binding.roomDropdown.showDropDown() }
        binding.roomDropdown.setOnFocusChangeListener { _, hasFocus ->
            if (hasFocus) binding.roomDropdown.showDropDown()
        }
    }

    private fun setupListeners() {
        binding.pickLocationButton.setOnClickListener {
            val intent = LocationPickerActivity.createIntent(this, null, null)
            pickLocationLauncher.launch(intent)
        }
        binding.messageText.setOnClickListener {
            binding.messageText.visibility = View.GONE
            viewModel.clearMessage()
        }
        binding.addLockButton.setOnClickListener {
            viewModel.addPendingLock()
        }
    }

    private fun enableForegroundDispatch() {
        val adapter = nfcAdapter ?: return
        val intent = Intent(this, javaClass).addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING)
        val pendingIntent = PendingIntent.getActivity(
            this,
            0,
            intent,
            PendingIntent.FLAG_MUTABLE
        )
        adapter.enableForegroundDispatch(this, pendingIntent, null, null)
    }

    private fun disableForegroundDispatch() {
        nfcAdapter?.disableForegroundDispatch(this)
    }

    companion object {
        fun createIntent(
            context: Context,
            lockNfcId: String? = null,
            roomId: Long? = null,
            mode: NfcOperationViewModel.Mode = NfcOperationViewModel.Mode.OPEN
        ): Intent {
            return Intent(context, NfcOperationActivity::class.java).apply {
                lockNfcId?.let { putExtra(NfcOperationViewModel.EXTRA_LOCK_NFC_ID, it) }
                roomId?.let { putExtra(NfcOperationViewModel.EXTRA_ROOM_ID, it) }
                putExtra(NfcOperationViewModel.EXTRA_ACTION, mode.name)
            }
        }
    }

    private data class RoomOption(val id: Long?, val label: String)
}
